// 导入 init 和 h 需要注意路径问题，不能完全参照官方文档
import { init } from 'snabbdom/build/init'
import { h } from 'snabbdom/build/h'

// 导入模块
import { classModule } from 'snabbdom/build/modules/class'
import { styleModule } from 'snabbdom/build/modules/style'
import { propsModule } from 'snabbdom/build/modules/props'
import { eventListenersModule } from 'snabbdom/build/modules/eventlisteners'

var originalData = [
  { rank: 1, title: 'The Shawshank Redemption', desc: 'Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency.', elmHeight: 0 },
  { rank: 2, title: 'The Godfather', desc: 'The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son.', elmHeight: 0 },
  { rank: 3, title: 'The Godfather: Part II', desc: 'The early life and career of Vito Corleone in 1920s New York is portrayed while his son, Michael, expands and tightens his grip on his crime syndicate stretching from Lake Tahoe, Nevada to pre-revolution 1958 Cuba.', elmHeight: 0 },
  { rank: 4, title: 'The Dark Knight', desc: 'When the menace known as the Joker wreaks havoc and chaos on the people of Gotham, the caped crusader must come to terms with one of the greatest psychological tests of his ability to fight injustice.', elmHeight: 0 },
  { rank: 5, title: 'Pulp Fiction', desc: 'The lives of two mob hit men, a boxer, a gangster\'s wife, and a pair of diner bandits intertwine in four tales of violence and redemption.', elmHeight: 0 },
  { rank: 6, title: 'Schindler\'s List', desc: 'In Poland during World War II, Oskar Schindler gradually becomes concerned for his Jewish workforce after witnessing their persecution by the Nazis.', elmHeight: 0 },
  { rank: 7, title: '12 Angry Men', desc: 'A dissenting juror in a murder trial slowly manages to convince the others that the case is not as obviously clear as it seemed in court.', elmHeight: 0 },
  { rank: 8, title: 'The Good, the Bad and the Ugly', desc: 'A bounty hunting scam joins two men in an uneasy alliance against a third in a race to find a fortune in gold buried in a remote cemetery.', elmHeight: 0 },
  { rank: 9, title: 'The Lord of the Rings: The Return of the King', desc: 'Gandalf and Aragorn lead the World of Men against Sauron\'s army to draw his gaze from Frodo and Sam as they approach Mount Doom with the One Ring.', elmHeight: 0 },
  { rank: 10, title: 'Fight Club', desc: 'An insomniac office worker looking for a way to change his life crosses paths with a devil-may-care soap maker and they form an underground fight club that evolves into something much, much more...', elmHeight: 0 },
]

let patch = init([classModule, propsModule, styleModule, eventListenersModule])

let data = originalData.slice(0, 10)

let vnode = null
let sortBy = 'rank'
let totalHeight = 0
let margin = 8

// 获取操作栏 vnode
function optionVnode() {
  return h('div', [
    h('a.btn.add', { on: { click: add } }, 'Add'),
    'Sort by: ',
    h('span.btn-group', [
      h('a.btn.rank', { class: { active: sortBy === 'rank' }, on: { click: () => { changeSort('rank') } } }, 'Rank'),
      h('a.btn.title', { class: { active: sortBy === 'title' }, on: { click: () => { changeSort('title') } } }, 'Title'),
      h('a.btn.desc', { class: { active: sortBy === 'desc' }, on: { click: () => { changeSort('description') } } }, 'Description'),
    ]),
  ])
}

// 获取单个movie vnode 内容
function movieVnode(movie) {
  return h('div.row', {
    key: movie.rank,
    style: {
      opacity: '0',
      transform: 'translate(-200px)',
      delayed: { transform: `translateY(${movie.offset}px)`, opacity: '1' },
      remove: { opacity: '0', transform: `translateY(${movie.offset}px) translateX(200px)` }
    },
    hook: { insert: (vnode) => { movie.elmHeight = vnode.elm.offsetHeight } },
  }, [
    h('div', { style: { fontWeight: 'bold' } }, movie.rank),
    h('div', movie.title),
    h('div', movie.desc),
    h('div.btn.rm-btn', { on: { click: () => { remove(movie) } } }, 'x'),
  ])
}

// 获取当前列表内容
function moviesVnode(data) {
  // 通过 data 来获取 vnode 内容
  return h('div.list', { style: { height: totalHeight + 'px' } }, data.map(movieVnode))

}

// 建立初始虚拟 dom 对象
// 主要由三部分组成：标题，操作栏，列表，并且由容器包裹
// 其中需要更新的部分为 操作栏的状态和列表内容
function view(data) {
  return h('div', [
    h('h1', 'Top 10 movies'),
    optionVnode(),
    moviesVnode(data)
  ])
}

// 添加数据
function add() {
  var n = originalData[Math.floor(Math.random() * 10)]
  data = [{ rank: data.length + 1, title: n.title, desc: n.desc, elmHeight: 0 }].concat(data)
  // 为何这里要渲染两次？初步猜测，第一次无法获取元素的高，只能渲染第二次来获取渲染新的node的高
  render()
  render()
}

// 移除
function remove(movie) {
  // 移除列表的元素，并重新渲染
  data = data.filter((m) => {
    return m !== movie
  })
  render()
}

// 进行列表排序
function changeSort(prop) {
  sortBy = prop
  // 通过某个键值进行列表排序
  data.sort((a, b) => {
    if (a[prop] > b[prop]) {
      return 1
    }
    if (a[prop] < b[prop]) {
      return -1
    }
    return 0
  })
  // 重新渲染
  render()
}

// 进行列表排序渲染
function render() {
  // 这里对原代码进行优化
  let h = margin
  data.forEach((item, i) => {
    item.offset = h
    h += item.elmHeight + margin
  })
  totalHeight = h
  vnode = patch(vnode, view(data))
}

// 初始化
window.addEventListener('DOMContentLoaded', () => {
  var app = document.querySelector('#container')
  vnode = patch(app, view(data))
  render()
})
